Skip to content

runtime: reserve 16GB of heap address space on 64-bit unix - #5644

Open
0pcom wants to merge 1 commit into
tinygo-org:devfrom
0magnet:unix-heap-reserve
Open

0pcom wants to merge 1 commit into
tinygo-org:devfrom
0magnet:unix-heap-reserve

Conversation

@0pcom

@0pcom 0pcom commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5760.

allocateHeap caps the heap at 1GB on every target, so with -gc=conservative or
-gc=precise any single allocation approaching 1GB fails with out of memory no
matter how much system RAM is free. The case that hit this was a 1GiB scrypt
key derivation buffer (N=1<<20, r=8) in the skycoin wallet, on a machine with
16GB free.

Reserve 16GB of virtual address space on 64-bit targets instead. The mmap is a
reservation, not a commitment. Pages cost physical memory only when first
touched, and the existing halve on failure loop still adapts when the map is
refused. 32-bit targets keep the 1GB cap. The growHeap comment already points
this way, in "If we run out of memory, we should consider increasing
heapMaxSize on 64-bit systems."

Verified on linux/amd64 with -gc=conservative. Before the change,
make([]byte, 1536<<20) gives a fatal out of memory error with 15GB free. After
it, the same allocation succeeds and is usable across the whole range.

One behavioral note. Under the blocks GC on 64-bit hosts the practical limit
becomes actual system memory, matching the boehm default and big Go, so true
exhaustion surfaces as OS memory pressure rather than a fatal error at an
arbitrary 1GB.

@0pcom
0pcom force-pushed the unix-heap-reserve branch from 68058ae to ae3954c Compare September 2, 2026 08:14
@0pcom

0pcom commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the CI failures: the 16GB literal did not compile on 32-bit targets (ARM/MIPS) — Go type-checks the dead branch too. The reservation size is now a constant derived from TargetBits (1 << (30 + 4*(TargetBits/64))): 16GB on 64-bit, the previous 1GB on 32-bit. Verified: linux/amd64 still allocates and uses a 1.5GiB buffer under -gc=conservative, and linux/arm + linux/mips cross-compile cleanly.

The heap reserved a flat 1GB of virtual address space, so any allocation
approaching 1GB failed regardless of how much memory the system had. One
example is a scrypt key derivation buffer with N=1<<20 and r=8.

The reservation is virtual, so pages cost physical RAM only when first
touched, and allocateHeap still halves its request if mmap refuses. 32-bit
targets keep the 1GB reserve.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime: a single allocation near 1GB fails on 64-bit unix regardless of free memory

1 participant